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

Merge branch 'new_api'

This commit is contained in:
William Woodall 2012-06-09 18:11:59 -05:00
commit eb3ebc1dc7
14 changed files with 1395 additions and 1089 deletions

2
.gitignore vendored
View File

@ -23,3 +23,5 @@ patched
wiped wiped
msg_gen msg_gen
srv_gen srv_gen
doc/html
*sublime-workspace

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.4.6)
set(ROS_ROOT $ENV{ROS_ROOT}) set(ROS_ROOT $ENV{ROS_ROOT})
option(SERIAL_BUILD_WIHOUT_ROS "Build without ROS?" OFF) option(SERIAL_BUILD_WIHOUT_ROS "Build without ROS?" ON)
if(DEFINED ROS_ROOT AND NOT SERIAL_BUILD_WIHOUT_ROS) if(DEFINED ROS_ROOT AND NOT SERIAL_BUILD_WIHOUT_ROS)
# Build with ROS # Build with ROS

View File

@ -70,7 +70,7 @@ Run the example:
The BSD License The BSD License
Copyright (c) 2011 William Woodall Copyright (c) 2012 William Woodall
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -37,7 +37,7 @@ PROJECT_NUMBER = 1.0
# for a project that appears at the top of each page and should give viewer # for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short. # a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = Cross-platform serial port library for C++ PROJECT_BRIEF = "Cross-platform serial port library for C++"
# With the PROJECT_LOGO tag one can specify an logo or icon that is # With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not # included in the documentation. The maximum height of the logo should not
@ -610,7 +610,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = include/serial include/serial/impl src src/impl INPUT = include src
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@ -634,7 +634,7 @@ FILE_PATTERNS =
# should be searched for input files as well. Possible values are YES and NO. # should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used. # If left blank NO is used.
RECURSIVE = NO RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should # The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a # excluded from the INPUT source files. This way you can easily exclude a

View File

@ -8,7 +8,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2011 William Woodall, John Harrison * Copyright (c) 2012 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"),
@ -54,7 +54,6 @@ class serial::Serial::SerialImpl {
public: public:
SerialImpl (const string &port, SerialImpl (const string &port,
unsigned long baudrate, unsigned long baudrate,
long timeout,
bytesize_t bytesize, bytesize_t bytesize,
parity_t parity, parity_t parity,
stopbits_t stopbits, stopbits_t stopbits,
@ -75,10 +74,10 @@ public:
available (); available ();
size_t size_t
read (unsigned char* buf, size_t size = 1); read (uint8_t *buf, size_t size = 1);
size_t size_t
write (const string &data); write (const uint8_t *data, size_t length);
void void
flush (); flush ();
@ -90,28 +89,31 @@ public:
flushOutput (); flushOutput ();
void void
sendBreak(int duration); sendBreak (int duration);
void void
setBreak(bool level); setBreak (bool level);
void void
setRTS(bool level); setRTS (bool level);
void void
setDTR(bool level); setDTR (bool level);
bool bool
getCTS(); waitForChange ();
bool bool
getDSR(); getCTS ();
bool bool
getRI(); getDSR ();
bool bool
getCD(); getRI ();
bool
getCD ();
void void
setPort (const string &port); setPort (const string &port);
@ -120,9 +122,9 @@ public:
getPort () const; getPort () const;
void void
setTimeout (long timeout); setTimeout (Timeout &timeout);
long Timeout
getTimeout () const; getTimeout () const;
void void
@ -156,16 +158,16 @@ public:
getFlowcontrol () const; getFlowcontrol () const;
void void
readLock(); readLock ();
void void
readUnlock(); readUnlock ();
void void
writeLock(); writeLock ();
void void
writeUnlock(); writeUnlock ();
protected: protected:
void reconfigurePort (); void reconfigurePort ();
@ -178,7 +180,7 @@ private:
bool xonxoff_; bool xonxoff_;
bool rtscts_; bool rtscts_;
long timeout_; // Timeout for read operations Timeout timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate unsigned long baudrate_; // Baudrate
parity_t parity_; // Parity parity_t parity_; // Parity

View File

@ -8,7 +8,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2011 William Woodall, John Harrison * Copyright (c) 2012 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"),
@ -39,6 +39,8 @@
#include "serial/serial.h" #include "serial/serial.h"
#include "windows.h"
namespace serial { namespace serial {
using std::string; using std::string;
@ -51,7 +53,6 @@ class serial::Serial::SerialImpl {
public: public:
SerialImpl (const string &port, SerialImpl (const string &port,
unsigned long baudrate, unsigned long baudrate,
long timeout,
bytesize_t bytesize, bytesize_t bytesize,
parity_t parity, parity_t parity,
stopbits_t stopbits, stopbits_t stopbits,
@ -72,10 +73,10 @@ public:
available (); available ();
size_t size_t
read (char* buf, size_t size = 1); read (uint8_t *buf, size_t size = 1);
size_t size_t
write (const string &data); write (const uint8_t *data, size_t length);
void void
flush (); flush ();
@ -87,28 +88,31 @@ public:
flushOutput (); flushOutput ();
void void
sendBreak(int duration); sendBreak (int duration);
void void
setBreak(bool level); setBreak (bool level);
void void
setRTS(bool level); setRTS (bool level);
void void
setDTR(bool level); setDTR (bool level);
bool bool
getCTS(); waitForChange ();
bool bool
getDSR(); getCTS ();
bool bool
getRI(); getDSR ();
bool bool
getCD(); getRI ();
bool
getCD ();
void void
setPort (const string &port); setPort (const string &port);
@ -117,9 +121,9 @@ public:
getPort () const; getPort () const;
void void
setTimeout (long timeout); setTimeout (Timeout &timeout);
long Timeout
getTimeout () const; getTimeout () const;
void void
@ -152,24 +156,39 @@ public:
flowcontrol_t flowcontrol_t
getFlowcontrol () const; getFlowcontrol () const;
void
readLock ();
void
readUnlock ();
void
writeLock ();
void
writeUnlock ();
protected: protected:
void reconfigurePort (); void reconfigurePort ();
private: private:
string port_; // Path to the file descriptor string port_; // Path to the file descriptor
int fd_; // The current file descriptor HANDLE fd_;
bool isOpen_; bool is_open_;
bool xonxoff_;
bool rtscts_;
long timeout_; // Timeout for read operations Timeout timeout_; // Timeout for read operations
unsigned long baudrate_; // Baudrate unsigned long baudrate_; // Baudrate
parity_t parity_; // Parity parity_t parity_; // Parity
bytesize_t bytesize_; // Size of the bytes bytesize_t bytesize_; // Size of the bytes
stopbits_t stopbits_; // Stop Bits stopbits_t stopbits_; // Stop Bits
flowcontrol_t flowcontrol_; // Flow Control flowcontrol_t flowcontrol_; // Flow Control
// Mutex used to lock the read functions
HANDLE read_mutex;
// Mutex used to lock the write functions
HANDLE write_mutex;
}; };
} }

View File

@ -8,7 +8,7 @@
* *
* The MIT License * The MIT License
* *
* Copyright (c) 2011 William Woodall * Copyright (c) 2012 William Woodall
* *
* 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"),
@ -38,12 +38,15 @@
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <string.h> #include <string>
#include <cstring>
#include <sstream> #include <sstream>
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include <serial/v8stdint.h>
#define THROW(exceptionClass, message) throw exceptionClass(__FILE__, __LINE__, (message) ) #define THROW(exceptionClass, message) throw exceptionClass(__FILE__, \
__LINE__, (message) )
namespace serial { namespace serial {
@ -83,27 +86,70 @@ typedef enum {
flowcontrol_software flowcontrol_software
} flowcontrol_t; } flowcontrol_t;
/*!
* Structure for setting the timeout of the serial port, times are
* in milliseconds.
*
* In order to disable the interbyte timeout, set it to Timeout::max().
*/
struct Timeout {
static uint32_t max() {return std::numeric_limits<uint32_t>::max();}
/*!
* Convenience function to generate Timeout structs using a
* single absolute timeout.
*
* \param timeout A long that defines the time in milliseconds until a
* timeout occurs after a call to read or write is made.
*
* \return Timeout struct that represents this simple timeout provided.
*/
static Timeout simpleTimeout(uint32_t timeout) {
return Timeout(max(), timeout, 0, timeout, 0);
}
/*! Number of milliseconds between bytes received to timeout on. */
uint32_t inter_byte_timeout;
/*! A constant number of milliseconds to wait after calling read. */
uint32_t read_timeout_constant;
/*! A multiplier against the number of requested bytes to wait after
* calling read.
*/
uint32_t read_timeout_multiplier;
/*! A constant number of milliseconds to wait after calling write. */
uint32_t write_timeout_constant;
/*! A multiplier against the number of requested bytes to wait after
* calling write.
*/
uint32_t write_timeout_multiplier;
Timeout (uint32_t inter_byte_timeout_=0, uint32_t read_timeout_constant_=0,
uint32_t read_timeout_multiplier_=0, uint32_t write_timeout_constant_=0,
uint32_t write_timeout_multiplier_=0)
: inter_byte_timeout(inter_byte_timeout_),
read_timeout_constant(read_timeout_constant_),
read_timeout_multiplier(read_timeout_multiplier_),
write_timeout_constant(write_timeout_constant_),
write_timeout_multiplier(write_timeout_multiplier_)
{}
};
/*! /*!
* Class that provides a portable serial port interface. * Class that provides a portable serial port interface.
*/ */
class Serial { class Serial {
public: public:
/*! /*!
* Constructor, creates a SerialPortBoost object and opens the port. * Creates a Serial object and opens the port if a port is specified,
* otherwise it remains closed until serial::Serial::open is called.
* *
* \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 unsigned 32-bit integer that represents the baudrate
* *
* \param timeout A long that represents the time (in milliseconds) until a * \param timeout A serial::Timeout struct that defines the timeout
* timeout on reads occur. Setting this to zero (0) will cause reading to * conditions for the serial port. \see serial::Timeout
* 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
* 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
* 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,
@ -119,14 +165,11 @@ 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 = "",
unsigned long baudrate = 9600, uint32_t baudrate = 9600,
long timeout = 0, Timeout timeout = Timeout(),
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,
@ -136,8 +179,8 @@ 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 port is set and the port isn't
* alreay open. * already 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.
@ -164,28 +207,82 @@ public:
/*! Return the number of characters in the buffer. */ /*! Return the number of characters in the buffer. */
size_t size_t
available(); available ();
/*! Read a given amount of bytes from the serial port. /*! Read a given amount of bytes from the serial port into a given buffer.
* *
* If a timeout is set it may return less characters than requested. With * The read function will return in one of three cases:
* no timeout it will block until the requested number of bytes have been * * The number of requested bytes was read.
* read or until an exception occurs. * * In this case the number of bytes requested will match the size_t
* returned by read.
* * A timeout occurred, in this case the number of bytes read will not
* match the amount requested, but no exception will be thrown. One of
* two possible timeouts occurred:
* * The inter byte timeout expired, this means that number of
* milliseconds elapsed between receiving bytes from the serial port
* exceeded the inter byte timeout.
* * The total timeout expired, which is calculated by multiplying the
* read timeout multiplier by the number of requested bytes and then
* added to the read timeout constant. If that total number of
* milliseconds elapses after the initial call to read a timeout will
* occur.
* * An exception occurred, in this case an actual exception will be thrown.
*
* \param buffer An uint8_t array of at least the requested size.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*/
size_t
read (uint8_t *buffer, size_t size);
/*! Read a given amount of bytes from the serial port into a give buffer.
*
* \param buffer A reference to a std::vector of uint8_t.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*/
size_t
read (std::vector<uint8_t> &buffer, size_t size = 1);
/*! Read a given amount of bytes from the serial port into a give buffer.
*
* \param buffer A reference to a std::string.
* \param size A size_t defining how many bytes to be read.
*
* \return A size_t representing the number of bytes read as a result of the
* call to read.
*/
size_t
read (std::string &buffer, size_t size = 1);
/*! Read a given amount of bytes from the serial port and return a string
* containing the data.
* *
* \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 from the port.
*/ */
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.
*
* \param buffer A std::string reference used to store the data.
* \param size A maximum length of a line, defaults to 65536 (2^16)
* \param eol A string to match against for the EOL.
*
* \return A size_t representing the number of bytes read.
*/
size_t
readline (std::string &buffer, size_t size = 65536, std::string eol = "\n");
/*! 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.
* *
@ -194,15 +291,10 @@ public:
* *
* \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 = 65536, 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 serial 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.
@ -218,160 +310,220 @@ public:
/*! Write a string to the serial port. /*! Write a string to the serial port.
* *
* \param data A const reference containg the data to be written * \param data A const reference containing the data to be written
* to the serial port.
*
* \param size A size_t that indicates how many bytes should be written from
* the given data buffer.
*
* \return A size_t representing the number of bytes actually written to
* the serial port.
*/
size_t
write (const uint8_t *data, size_t size);
/*! Write a string to the serial port.
*
* \param data A const reference containing 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 size_t
write (const unsigned char *data, size_t size); write (const std::vector<uint8_t> &data);
size_t
write (const std::vector<unsigned char> &data); /*! Write a string to the serial port.
*
* \param data A const reference containing the data to be written
* to the serial port.
*
* \return A size_t representing the number of bytes actually written to
* the serial port.
*/
size_t size_t
write (const std::string &data); write (const std::string &data);
/*! Sets the serial port identifier. /*! Sets the serial port identifier.
* *
* \param port A const std::string reference containing the address of the * \param port A const std::string reference containing the address of the
* serial port, which would be something like 'COM1' on Windows and * serial port, which would be something like 'COM1' on Windows and
* '/dev/ttyS0' on Linux. * '/dev/ttyS0' on Linux.
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setPort (const std::string &port); setPort (const std::string &port);
/*! Gets the serial port identifier. /*! Gets the serial port identifier.
* *
* \see Serial::setPort * \see Serial::setPort
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
std::string std::string
getPort () const; getPort () const;
/*! Sets the timeout for reads in milliseconds. /*! Sets the timeout for reads and writes using the Timeout struct.
* *
* \param timeout A long that represents the time (in milliseconds) until a * There are two timeout conditions described here:
* timeout on reads occur. Setting this to zero (0) will cause reading to be * * The inter byte timeout:
* non-blocking, i.e. the available data will be returned immediately, but it * * The inter_byte_timeout component of serial::Timeout defines the
* will not block to wait for more. Setting this to a number less than * maximum amount of time, in milliseconds, between receiving bytes on
* zero (-1) will result in infinite blocking behaviour, i.e. the serial port * the serial port that can pass before a timeout occurs. Setting this
* will block until either size bytes have been read or an exception has * to zero will prevent inter byte timeouts from occurring.
* occured. * * Total time timeout:
*/ * * The the constant and multiplier component of this timeout condition,
* for both read and write, are defined in serial::Timeout. This
* timeout occurs if the total time since the read or write call was
* made exceeds the specified time in milliseconds.
* * The limit is defined by multiplying the multiplier component by the
* number of requested bytes and adding that product to the constant
* component. In this way if you want a read call, for example, to
* timeout after exactly one second regardless of the number of bytes
* you asked for then set the read_timeout_constant component of
* serial::Timeout to 1000 and the read_timeout_multiplier to zero.
* This timeout condition can be used in conjunction with the inter
* byte timeout condition with out any problems, timeout will simply
* occur when one of the two timeout conditions is met. This allows
* users to have maximum control over the trade-off between
* responsiveness and efficiency.
*
* Read and write functions will return in one of three cases. When the
* reading or writing is complete, when a timeout occurs, or when an
* exception occurs.
*
* \param timeout A serial::Timeout struct containing the inter byte
* timeout, and the read and write timeout constants and multipliers.
*
* \see serial::Timeout
*/
void void
setTimeout (long timeout); setTimeout (Timeout &timeout);
/*! Sets the timeout for reads and writes. */
void
setTimeout (uint32_t inter_byte_timeout, uint32_t read_timeout_constant,
uint32_t read_timeout_multiplier, uint32_t write_timeout_constant,
uint32_t write_timeout_multiplier)
{
Timeout timeout(inter_byte_timeout, read_timeout_constant,
read_timeout_multiplier, write_timeout_constant,
write_timeout_multiplier);
return setTimeout(timeout);
}
/*! Gets the timeout for reads in seconds. /*! Gets the timeout for reads in seconds.
* *
* \see Serial::setTimeout * \return A Timeout struct containing the inter_byte_timeout, and read
*/ * and write timeout constants and multipliers.
long *
* \see Serial::setTimeout
*/
Timeout
getTimeout () const; getTimeout () const;
/*! Sets the baudrate for the serial port. /*! Sets the baudrate for the serial port.
* *
* Possible baudrates depends on the system but some safe baudrates include: * Possible baudrates depends on the system but some safe baudrates include:
* 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000, * 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 56000,
* 57600, 115200 * 57600, 115200
* Some other baudrates that are supported by some comports: * Some other baudrates that are supported by some comports:
* 128000, 153600, 230400, 256000, 460800, 921600 * 128000, 153600, 230400, 256000, 460800, 921600
* *
* \param baudrate An integer that sets the baud rate for the serial port. * \param baudrate An integer that sets the baud rate for the serial port.
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setBaudrate (unsigned long baudrate); setBaudrate (uint32_t baudrate);
/*! Gets the baudrate for the serial port. /*! Gets the baudrate for the serial port.
* *
* \return An integer that sets the baud rate for the serial port. * \return An integer that sets the baud rate for the serial port.
* *
* \see Serial::setBaudrate * \see Serial::setBaudrate
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
unsigned long uint32_t
getBaudrate () const; getBaudrate () const;
/*! Sets the bytesize for the serial port. /*! Sets the bytesize for the serial port.
* *
* \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
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setBytesize (bytesize_t bytesize); setBytesize (bytesize_t bytesize);
/*! Gets the bytesize for the serial port. /*! Gets the bytesize for the serial port.
* *
* \see Serial::setBytesize * \see Serial::setBytesize
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
bytesize_t bytesize_t
getBytesize () const; getBytesize () const;
/*! Sets the parity for the serial port. /*! Sets the parity for the serial port.
* *
* \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
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setParity (parity_t parity); setParity (parity_t parity);
/*! Gets the parity for the serial port. /*! Gets the parity for the serial port.
* *
* \see Serial::setParity * \see Serial::setParity
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
parity_t parity_t
getParity () const; getParity () const;
/*! Sets the stopbits for the serial port. /*! Sets the stopbits for the serial port.
* *
* \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
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setStopbits (stopbits_t stopbits); setStopbits (stopbits_t stopbits);
/*! Gets the stopbits for the serial port. /*! Gets the stopbits for the serial port.
* *
* \see Serial::setStopbits * \see Serial::setStopbits
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
stopbits_t stopbits_t
getStopbits () const; getStopbits () const;
/*! Sets the flow control for the serial port. /*! Sets the flow control for the serial port.
* *
* \param flowcontrol Type of flowcontrol used, default is flowcontrol_none, * \param flowcontrol Type of flowcontrol used, default is flowcontrol_none,
* possible values are: flowcontrol_none, flowcontrol_software, * possible values are: flowcontrol_none, flowcontrol_software,
* flowcontrol_hardware * flowcontrol_hardware
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
void void
setFlowcontrol (flowcontrol_t flowcontrol); setFlowcontrol (flowcontrol_t flowcontrol);
/*! Gets the flow control for the serial port. /*! Gets the flow control for the serial port.
* *
* \see Serial::setFlowcontrol * \see Serial::setFlowcontrol
* *
* \throw InvalidConfigurationException * \throw InvalidConfigurationException
*/ */
flowcontrol_t flowcontrol_t
getFlowcontrol () const; getFlowcontrol () const;
@ -387,27 +539,52 @@ public:
void void
flushOutput (); flushOutput ();
/*! Sends the RS-232 break signal. See tcsendbreak(3). */
void void
sendBreak (int duration); sendBreak (int duration);
/*! Set the break condition to a given level. Defaults to true. */
void void
setBreak (bool level = true); setBreak (bool level = true);
/*! Set the RTS handshaking line to the given level. Defaults to true. */
void void
setRTS (bool level = true); setRTS (bool level = true);
/*! Set the DTR handshaking line to the given level. Defaults to true. */
void void
setDTR (bool level = true); setDTR (bool level = true);
/*!
* Blocks until CTS, DSR, RI, CD changes or something interrupts it.
*
* Can throw an exception if an error occurs while waiting.
* You can check the status of CTS, DSR, RI, and CD once this returns.
* Uses TIOCMIWAIT via ioctl if available (mostly only on Linux) with a
* resolution of less than +-1ms and as good as +-0.2ms. Otherwise a
* polling method is used which can give +-2ms.
*
* \return Returns true if one of the lines changed, false if something else
* occurred.
*
* \throw SerialException
*/
bool
waitForChange ();
/*! Returns the current status of the CTS line. */
bool bool
getCTS (); getCTS ();
/*! Returns the current status of the DSR line. */
bool bool
getDSR (); getDSR ();
/*! Returns the current status of the RI line. */
bool bool
getRI (); getRI ();
/*! Returns the current status of the CD line. */
bool bool
getCD (); getCD ();
@ -429,15 +606,24 @@ private:
// Read common function // Read common function
size_t size_t
read_ (unsigned char *buffer, size_t size); read_ (uint8_t *buffer, size_t size);
// Write common function
size_t
write_ (const uint8_t *data, size_t length);
}; };
class SerialExecption : public std::exception class SerialExecption : public std::exception
{ {
// Disable copy constructors
void operator=(const SerialExecption&);
const SerialExecption& operator=(SerialExecption);
const char* e_what_; const char* e_what_;
public: public:
SerialExecption (const char *description) : e_what_ (description) {} SerialExecption (const char *description) : e_what_ (description) {}
SerialExecption (const SerialExecption& other) {
e_what_ = other.e_what_;
}
virtual const char* what () const throw () virtual const char* what () const throw ()
{ {
@ -449,6 +635,9 @@ public:
class IOException : public std::exception class IOException : public std::exception
{ {
// Disable copy constructors
void operator=(const IOException&);
const IOException& operator=(IOException);
std::string file_; std::string file_;
int line_; int line_;
const char* e_what_; const char* e_what_;
@ -459,6 +648,9 @@ public:
explicit IOException (std::string file, int line, const char * description) explicit IOException (std::string file, int line, const char * description)
: file_(file), line_(line), e_what_ (description), errno_(0) {} : file_(file), line_(line), e_what_ (description), errno_(0) {}
virtual ~IOException() throw() {} virtual ~IOException() throw() {}
IOException (const IOException& other) {
e_what_ = other.e_what_;
}
int getErrorNumber () { return errno_; } int getErrorNumber () { return errno_; }
@ -476,9 +668,15 @@ public:
class PortNotOpenedException : public std::exception class PortNotOpenedException : public std::exception
{ {
// Disable copy constructors
void operator=(const PortNotOpenedException&);
const PortNotOpenedException& operator=(PortNotOpenedException);
const char * e_what_; const char * e_what_;
public: public:
PortNotOpenedException (const char * description) : e_what_ (description) {} PortNotOpenedException (const char * description) : e_what_ (description) {}
PortNotOpenedException (const PortNotOpenedException& other) {
e_what_ = other.e_what_;
}
virtual const char* what () const throw () virtual const char* what () const throw ()
{ {
@ -488,11 +686,6 @@ public:
} }
}; };
class SerialExceptionBase : public std::exception
{
};
} // namespace serial } // namespace serial
#endif #endif

57
include/serial/v8stdint.h Normal file
View File

@ -0,0 +1,57 @@
// This header is from the v8 google project:
// http://code.google.com/p/v8/source/browse/trunk/include/v8stdint.h
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Load definitions of standard types.
#ifndef V8STDINT_H_
#define V8STDINT_H_
#include <stddef.h>
#include <stdio.h>
#if defined(_WIN32) && !defined(__MINGW32__)
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t; // NOLINT
typedef unsigned short uint16_t; // NOLINT
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
// intptr_t and friends are defined in crtdefs.h through stdio.h.
#else
#include <stdint.h>
#endif
#endif // V8STDINT_H_

View File

@ -122,6 +122,7 @@ macro(build_serial)
) )
INSTALL(FILES include/serial/serial.h INSTALL(FILES include/serial/serial.h
include/serial/v8stdint.h
DESTINATION include/serial) DESTINATION include/serial)
IF(NOT CMAKE_FIND_INSTALL_PATH) IF(NOT CMAKE_FIND_INSTALL_PATH)

20
serial.sublime-project Normal file
View File

@ -0,0 +1,20 @@
{
"word_wrap": "on",
"wrap_width": 80,
"folders":
[
{
"path": "/Users/william/devel/serial"
}
],
"settings":
{
"sublimeclang_options":
[
"-I/usr/include",
"-I/usr/local/include",
// "-I/usr/lib/clang/3.1/include/",
"-I${folder:${project_path:serial.sublime-project}}/include"
]
}
}

View File

@ -2,9 +2,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sstream>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/signal.h>
#include <errno.h> #include <errno.h>
#include <paths.h> #include <paths.h>
#include <sysexits.h> #include <sysexits.h>
@ -35,6 +37,7 @@
#endif #endif
using std::string; using std::string;
using std::stringstream;
using std::invalid_argument; using std::invalid_argument;
using serial::Serial; using serial::Serial;
using serial::SerialExecption; using serial::SerialExecption;
@ -43,12 +46,12 @@ using serial::IOException;
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate, Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
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)
: port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (true), rtscts_ (false), : port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (true), rtscts_ (false),
timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), baudrate_ (baudrate), parity_ (parity),
bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol) bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
{ {
pthread_mutex_init(&this->read_mutex, NULL); pthread_mutex_init(&this->read_mutex, NULL);
pthread_mutex_init(&this->write_mutex, NULL); pthread_mutex_init(&this->write_mutex, NULL);
@ -66,30 +69,26 @@ Serial::SerialImpl::~SerialImpl ()
void void
Serial::SerialImpl::open () Serial::SerialImpl::open ()
{ {
if (port_.empty ()) if (port_.empty ()) {
{
throw invalid_argument ("Empty port is invalid."); throw invalid_argument ("Empty port is invalid.");
} }
if (is_open_ == true) if (is_open_ == true) {
{
throw SerialExecption ("Serial 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);
if (fd_ == -1) if (fd_ == -1) {
{ switch (errno) {
switch (errno) case EINTR:
{ // Recurse because this is a recoverable error.
case EINTR: open ();
// Recurse because this is a recoverable error. return;
open (); case ENFILE:
return; case EMFILE:
case ENFILE: THROW (IOException, "Too many file handles open.");
case EMFILE: default:
THROW (IOException, "Too many file handles open."); THROW (IOException, errno);
default:
THROW (IOException, errno);
} }
} }
@ -100,26 +99,24 @@ 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, is the serial port open?"); 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
if (tcgetattr(fd_, &options) == -1) if (tcgetattr(fd_, &options) == -1) {
{
THROW (IOException, "::tcgetattr"); THROW (IOException, "::tcgetattr");
} }
// 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|ECHONL| options.c_lflag &= (unsigned long) ~(ICANON | ECHO | ECHOE | ECHOK | 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);
#ifdef IUCLC #ifdef IUCLC
options.c_iflag &= (unsigned long) ~IUCLC; options.c_iflag &= (unsigned long) ~IUCLC;
#endif #endif
@ -130,122 +127,118 @@ Serial::SerialImpl::reconfigurePort ()
// setup baud rate // setup baud rate
bool custom_baud = false; bool custom_baud = false;
speed_t baud; speed_t baud;
switch (baudrate_) switch (baudrate_) {
{
#ifdef B0 #ifdef B0
case 0: baud = B0; break; case 0: baud = B0; break;
#endif #endif
#ifdef B50 #ifdef B50
case 50: baud = B50; break; case 50: baud = B50; break;
#endif #endif
#ifdef B75 #ifdef B75
case 75: baud = B75; break; case 75: baud = B75; break;
#endif #endif
#ifdef B110 #ifdef B110
case 110: baud = B110; break; case 110: baud = B110; break;
#endif #endif
#ifdef B134 #ifdef B134
case 134: baud = B134; break; case 134: baud = B134; break;
#endif #endif
#ifdef B150 #ifdef B150
case 150: baud = B150; break; case 150: baud = B150; break;
#endif #endif
#ifdef B200 #ifdef B200
case 200: baud = B200; break; case 200: baud = B200; break;
#endif #endif
#ifdef B300 #ifdef B300
case 300: baud = B300; break; case 300: baud = B300; break;
#endif #endif
#ifdef B600 #ifdef B600
case 600: baud = B600; break; case 600: baud = B600; break;
#endif #endif
#ifdef B1200 #ifdef B1200
case 1200: baud = B1200; break; case 1200: baud = B1200; break;
#endif #endif
#ifdef B1800 #ifdef B1800
case 1800: baud = B1800; break; case 1800: baud = B1800; break;
#endif #endif
#ifdef B2400 #ifdef B2400
case 2400: baud = B2400; break; case 2400: baud = B2400; break;
#endif #endif
#ifdef B4800 #ifdef B4800
case 4800: baud = B4800; break; case 4800: baud = B4800; break;
#endif #endif
#ifdef B7200 #ifdef B7200
case 7200: baud = B7200; break; case 7200: baud = B7200; break;
#endif #endif
#ifdef B9600 #ifdef B9600
case 9600: baud = B9600; break; case 9600: baud = B9600; break;
#endif #endif
#ifdef B14400 #ifdef B14400
case 14400: baud = B14400; break; case 14400: baud = B14400; break;
#endif #endif
#ifdef B19200 #ifdef B19200
case 19200: baud = B19200; break; case 19200: baud = B19200; break;
#endif #endif
#ifdef B28800 #ifdef B28800
case 28800: baud = B28800; break; case 28800: baud = B28800; break;
#endif #endif
#ifdef B57600 #ifdef B57600
case 57600: baud = B57600; break; case 57600: baud = B57600; break;
#endif #endif
#ifdef B76800 #ifdef B76800
case 76800: baud = B76800; break; case 76800: baud = B76800; break;
#endif #endif
#ifdef B38400 #ifdef B38400
case 38400: baud = B38400; break; case 38400: baud = B38400; break;
#endif #endif
#ifdef B115200 #ifdef B115200
case 115200: baud = B115200; break; case 115200: baud = B115200; break;
#endif #endif
#ifdef B128000 #ifdef B128000
case 128000: baud = B128000; break; case 128000: baud = B128000; break;
#endif #endif
#ifdef B153600 #ifdef B153600
case 153600: baud = B153600; break; case 153600: baud = B153600; break;
#endif #endif
#ifdef B230400 #ifdef B230400
case 230400: baud = B230400; break; case 230400: baud = B230400; break;
#endif #endif
#ifdef B256000 #ifdef B256000
case 256000: baud = B256000; break; case 256000: baud = B256000; break;
#endif #endif
#ifdef B460800 #ifdef B460800
case 460800: baud = B460800; break; case 460800: baud = B460800; break;
#endif #endif
#ifdef B921600 #ifdef B921600
case 921600: baud = B921600; break; case 921600: baud = B921600; break;
#endif #endif
default: default:
custom_baud = true; custom_baud = true;
// Mac OS X 10.x Support // Mac OS X 10.x Support
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
#define IOSSIOSPEED _IOW('T', 2, speed_t) #define IOSSIOSPEED _IOW('T', 2, speed_t)
int new_baud = static_cast<int> (baudrate_); int new_baud = static_cast<int> (baudrate_);
if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0) if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0) {
{ THROW (IOException, errno);
THROW (IOException, errno); }
} // Linux Support
// Linux Support
#elif defined(__linux__) #elif defined(__linux__)
struct serial_struct ser; struct serial_struct ser;
ioctl (fd_, TIOCGSERIAL, &ser); ioctl (fd_, TIOCGSERIAL, &ser);
// set custom divisor // set custom divisor
ser.custom_divisor = ser.baud_base / baudrate_; ser.custom_divisor = ser.baud_base / baudrate_;
// update flags // update flags
ser.flags &= ~ASYNC_SPD_MASK; ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST; ser.flags |= ASYNC_SPD_CUST;
if (ioctl (fd_, TIOCSSERIAL, ser) < 0) if (ioctl (fd_, TIOCSSERIAL, ser) < 0) {
{ THROW (IOException, errno);
THROW (IOException, errno); }
}
#else #else
throw invalid_argument ("OS does not currently support custom bauds"); throw invalid_argument ("OS does not currently support custom bauds");
#endif #endif
} }
if (custom_baud == false) if (custom_baud == false) {
{
#ifdef _BSD_SOURCE #ifdef _BSD_SOURCE
::cfsetspeed(&options, baud); ::cfsetspeed(&options, baud);
#else #else
@ -257,56 +250,49 @@ Serial::SerialImpl::reconfigurePort ()
// setup char len // setup char len
options.c_cflag &= (unsigned long) ~CSIZE; options.c_cflag &= (unsigned long) ~CSIZE;
if (bytesize_ == eightbits) if (bytesize_ == eightbits)
options.c_cflag |= CS8; options.c_cflag |= CS8;
else if (bytesize_ == sevenbits) else if (bytesize_ == sevenbits)
options.c_cflag |= CS7; options.c_cflag |= CS7;
else if (bytesize_ == sixbits) else if (bytesize_ == sixbits)
options.c_cflag |= CS6; options.c_cflag |= CS6;
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);
else if (stopbits_ == stopbits_one_point_five) else if (stopbits_ == stopbits_one_point_five)
// ONE POINT FIVE 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); options.c_cflag |= (CSTOPB);
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);
{ } else {
options.c_cflag |= (PARENB|PARODD);
}
else
{
throw invalid_argument ("invalid parity"); throw invalid_argument ("invalid parity");
} }
// setup flow control // setup flow control
// xonxoff // xonxoff
#ifdef IXANY #ifdef IXANY
if (xonxoff_) if (xonxoff_)
options.c_iflag |= (IXON|IXOFF); //|IXANY) options.c_iflag |= (IXON | IXOFF); //|IXANY)
else else
options.c_iflag &= (unsigned long) ~(IXON|IXOFF|IXANY); options.c_iflag &= (unsigned long) ~(IXON | IXOFF | IXANY);
#else #else
if (xonxoff_) if (xonxoff_)
options.c_iflag |= (IXON|IXOFF); options.c_iflag |= (IXON | IXOFF);
else else
options.c_iflag &= (unsigned long) ~(IXON|IXOFF); options.c_iflag &= (unsigned long) ~(IXON | IXOFF);
#endif #endif
// rtscts // rtscts
#ifdef CRTSCTS #ifdef CRTSCTS
@ -337,10 +323,8 @@ Serial::SerialImpl::reconfigurePort ()
void void
Serial::SerialImpl::close () Serial::SerialImpl::close ()
{ {
if (is_open_ == 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;
} }
@ -357,23 +341,20 @@ Serial::SerialImpl::isOpen () const
size_t size_t
Serial::SerialImpl::available () Serial::SerialImpl::available ()
{ {
if (!is_open_) if (!is_open_) {
{
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 static_cast<size_t> (count); return static_cast<size_t> (count);
} } else {
else
{
THROW (IOException, errno); THROW (IOException, errno);
} }
} }
inline void get_time_now(struct timespec &time) { inline void get_time_now(struct timespec &time)
{
# ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time # ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock; clock_serv_t cclock;
mach_timespec_t mts; mach_timespec_t mts;
@ -388,53 +369,70 @@ inline void get_time_now(struct timespec &time) {
} }
size_t size_t
Serial::SerialImpl::read (unsigned char* buf, size_t size) Serial::SerialImpl::read (uint8_t *buf, size_t size)
{ {
if (!is_open_) // If the port is not open, throw
{ if (!is_open_) {
throw PortNotOpenedException ("Serial::read"); throw PortNotOpenedException ("Serial::read");
} }
fd_set readfds; fd_set readfds;
size_t bytes_read = 0; size_t bytes_read = 0;
struct timeval timeout; // Setup the total_timeout timeval
timeout.tv_sec = timeout_ / 1000; // This timeout is maximum time before a timeout after read is called
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000; struct timeval total_timeout;
while (bytes_read < size) // Calculate total timeout in milliseconds t_c + (t_m * N)
{ long total_timeout_ms = timeout_.read_timeout_constant;
total_timeout_ms += timeout_.read_timeout_multiplier*static_cast<long>(size);
total_timeout.tv_sec = total_timeout_ms / 1000;
total_timeout.tv_usec = static_cast<int>(total_timeout_ms % 1000);
total_timeout.tv_usec *= 1000; // To convert to micro seconds
// Setup the inter byte timeout
struct timeval inter_byte_timeout;
inter_byte_timeout.tv_sec = timeout_.inter_byte_timeout / 1000;
inter_byte_timeout.tv_usec =
static_cast<int> (timeout_.inter_byte_timeout % 1000);
inter_byte_timeout.tv_usec *= 1000; // To convert to micro seconds
while (bytes_read < size) {
// Setup the select timeout timeval
struct timeval timeout;
// If the total_timeout is less than the inter_byte_timeout
if (total_timeout.tv_sec < inter_byte_timeout.tv_sec
|| (total_timeout.tv_sec == inter_byte_timeout.tv_sec
&& total_timeout.tv_usec < inter_byte_timeout.tv_sec))
{
// Then set the select timeout to use the total time
timeout = total_timeout;
} else {
// Else set the select timeout to use the inter byte time
timeout = inter_byte_timeout;
}
FD_ZERO (&readfds); FD_ZERO (&readfds);
FD_SET (fd_, &readfds); FD_SET (fd_, &readfds);
// 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
// does not occur.
#if !defined(__linux__)
// Begin timing select // Begin timing select
struct timespec start, end; struct timespec start, end;
get_time_now(start); get_time_now (start);
#endif // Call select to block for serial data or a timeout
// Do the select
int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout); int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout);
#if !defined(__linux__)
// Calculate difference and update the structure // Calculate difference and update the structure
get_time_now(end); get_time_now (end);
// Calculate the time select took // Calculate the time select took
struct timeval diff; struct timeval diff;
diff.tv_sec = end.tv_sec-start.tv_sec; diff.tv_sec = end.tv_sec - start.tv_sec;
diff.tv_usec = static_cast<int> ((end.tv_nsec-start.tv_nsec)/1000); diff.tv_usec = static_cast<int> ((end.tv_nsec - start.tv_nsec) / 1000);
// Update the timeout // Update the timeout
if (timeout.tv_sec <= diff.tv_sec) { if (total_timeout.tv_sec <= diff.tv_sec) {
timeout.tv_sec = 0; total_timeout.tv_sec = 0;
} else { } else {
timeout.tv_sec -= diff.tv_sec; total_timeout.tv_sec -= diff.tv_sec;
} }
if (timeout.tv_usec <= diff.tv_usec) { if (total_timeout.tv_usec <= diff.tv_usec) {
timeout.tv_usec = 0; total_timeout.tv_usec = 0;
} else { } else {
timeout.tv_usec -= diff.tv_usec; total_timeout.tv_usec -= diff.tv_usec;
} }
#endif
// Figure out what happened by looking at select's response 'r' // Figure out what happened by looking at select's response 'r'
/** Error **/ /** Error **/
if (r < 0) { if (r < 0) {
// Select was interrupted, try again // Select was interrupted, try again
if (errno == EINTR) { if (errno == EINTR) {
@ -443,22 +441,21 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size)
// Otherwise there was some error // Otherwise there was some error
THROW (IOException, errno); THROW (IOException, errno);
} }
/** Timeout **/ /** Timeout **/
if (r == 0) { if (r == 0) {
break; break;
} }
/** Something ready to read **/ /** Something ready to read **/
if (r > 0) { if (r > 0) {
// Make sure our file descriptor is in the ready to read list // Make sure our file descriptor is in the ready to read list
if (FD_ISSET (fd_, &readfds)) { if (FD_ISSET (fd_, &readfds)) {
// This should be non-blocking returning only what is avaialble now // This should be non-blocking returning only what is available now
// Then returning so that select can block again. // Then returning so that select can block again.
ssize_t bytes_read_now = ssize_t bytes_read_now =
::read (fd_, buf+bytes_read, size-bytes_read); ::read (fd_, buf + bytes_read, size - 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 (bytes_read_now < 1) if (bytes_read_now < 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.
@ -484,21 +481,111 @@ Serial::SerialImpl::read (unsigned char* buf, size_t size)
} }
// This shouldn't happen, if r > 0 our fd has to be in the list! // 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" THROW (IOException, "select reports ready to read, but our fd isn't"
" in the list, this shouldn't happen!"); " in the list, this shouldn't happen!");
} }
} }
return bytes_read; return bytes_read;
} }
size_t size_t
Serial::SerialImpl::write (const string &data) Serial::SerialImpl::write (const uint8_t *data, size_t length)
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::write"); throw PortNotOpenedException ("Serial::write");
} }
fd_set writefds;
size_t bytes_written = 0;
struct timeval timeout;
timeout.tv_sec = timeout_.write_timeout_constant / 1000;
timeout.tv_usec = static_cast<int> (timeout_.write_timeout_multiplier % 1000);
timeout.tv_usec *= 1000; // To convert to micro seconds
while (bytes_written < length) {
FD_ZERO (&writefds);
FD_SET (fd_, &writefds);
// 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
// does not occur.
#if !defined(__linux__)
// Begin timing select
struct timespec start, end;
get_time_now(start);
#endif
// Do the select
int r = select (fd_ + 1, &writefds, 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 = static_cast<int> ((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
return static_cast<size_t> (::write (fd_, data.c_str (), data.length ())); // Figure out what happened by looking at select's response 'r'
/** Error **/
if (r < 0) {
// Select was interrupted, try again
if (errno == EINTR) {
continue;
}
// Otherwise there was some error
THROW (IOException, errno);
}
/** Timeout **/
if (r == 0) {
break;
}
/** Something ready to read **/
if (r > 0) {
// Make sure our file descriptor is in the ready to read list
if (FD_ISSET (fd_, &writefds)) {
// This should be non-blocking returning only what is avaialble now
// Then returning so that select can block again.
ssize_t bytes_written_now =
::write (fd_, data + bytes_written, length - bytes_written);
// read should always return some data as select reported it was
// ready to read when we get to this point.
if (bytes_written_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 write but "
"returned no data (device disconnected?)");
}
// Update bytes_read
bytes_written += static_cast<size_t> (bytes_written_now);
// If bytes_read == size then we have read everything we need
if (bytes_written == length) {
break;
}
// If bytes_read < size then we have more to read
if (bytes_written < length) {
continue;
}
// If bytes_read > size then we have over read, which shouldn't happen
if (bytes_written > length) {
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 bytes_written;
} }
void void
@ -514,12 +601,12 @@ Serial::SerialImpl::getPort () const
} }
void void
Serial::SerialImpl::setTimeout (long timeout) Serial::SerialImpl::setTimeout (serial::Timeout &timeout)
{ {
timeout_ = timeout; timeout_ = timeout;
} }
long serial::Timeout
Serial::SerialImpl::getTimeout () const Serial::SerialImpl::getTimeout () const
{ {
return timeout_; return timeout_;
@ -598,8 +685,7 @@ Serial::SerialImpl::getFlowcontrol () const
void void
Serial::SerialImpl::flush () Serial::SerialImpl::flush ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::flush"); throw PortNotOpenedException ("Serial::flush");
} }
tcdrain (fd_); tcdrain (fd_);
@ -608,8 +694,7 @@ Serial::SerialImpl::flush ()
void void
Serial::SerialImpl::flushInput () Serial::SerialImpl::flushInput ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::flushInput"); throw PortNotOpenedException ("Serial::flushInput");
} }
tcflush (fd_, TCIFLUSH); tcflush (fd_, TCIFLUSH);
@ -618,8 +703,7 @@ Serial::SerialImpl::flushInput ()
void void
Serial::SerialImpl::flushOutput () Serial::SerialImpl::flushOutput ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::flushOutput"); throw PortNotOpenedException ("Serial::flushOutput");
} }
tcflush (fd_, TCOFLUSH); tcflush (fd_, TCOFLUSH);
@ -628,25 +712,21 @@ Serial::SerialImpl::flushOutput ()
void void
Serial::SerialImpl::sendBreak (int duration) Serial::SerialImpl::sendBreak (int duration)
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::sendBreak"); throw PortNotOpenedException ("Serial::sendBreak");
} }
tcsendbreak (fd_, static_cast<int> (duration/4)); tcsendbreak (fd_, static_cast<int> (duration / 4));
} }
void void
Serial::SerialImpl::setBreak (bool level) Serial::SerialImpl::setBreak (bool level)
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::setBreak"); throw PortNotOpenedException ("Serial::setBreak");
} }
if (level) if (level) {
{
ioctl (fd_, TIOCSBRK); ioctl (fd_, TIOCSBRK);
} } else {
else {
ioctl (fd_, TIOCCBRK); ioctl (fd_, TIOCCBRK);
} }
} }
@ -654,15 +734,12 @@ Serial::SerialImpl::setBreak (bool level)
void void
Serial::SerialImpl::setRTS (bool level) Serial::SerialImpl::setRTS (bool level)
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::setRTS"); 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);
} }
} }
@ -670,25 +747,45 @@ Serial::SerialImpl::setRTS (bool level)
void void
Serial::SerialImpl::setDTR (bool level) Serial::SerialImpl::setDTR (bool level)
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::setDTR"); 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::waitForChange ()
{
#ifndef TIOCMIWAIT
while (is_open_ == true) {
int s = ioctl (fd_, TIOCMGET, 0);
if ((s & TIOCM_CTS) != 0) return true;
if ((s & TIOCM_DSR) != 0) return true;
if ((s & TIOCM_RI) != 0) return true;
if ((s & TIOCM_CD) != 0) return true;
usleep(1000);
}
#else
if (ioctl(fd_, TIOCMIWAIT, (TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS)) != 0) {
stringstream ss;
ss << "waitForDSR failed on a call to ioctl(TIOCMIWAIT): "
<< errno << " " << strerror(errno);
throw(SerialExecption(ss.str().c_str()));
return false;
}
return true;
#endif
return false;
}
bool bool
Serial::SerialImpl::getCTS () Serial::SerialImpl::getCTS ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::getCTS"); throw PortNotOpenedException ("Serial::getCTS");
} }
int s = ioctl (fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
@ -696,10 +793,9 @@ Serial::SerialImpl::getCTS ()
} }
bool bool
Serial::SerialImpl::getDSR() Serial::SerialImpl::getDSR ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::getDSR"); throw PortNotOpenedException ("Serial::getDSR");
} }
int s = ioctl (fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
@ -707,10 +803,9 @@ Serial::SerialImpl::getDSR()
} }
bool bool
Serial::SerialImpl::getRI() Serial::SerialImpl::getRI ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::getRI"); throw PortNotOpenedException ("Serial::getRI");
} }
int s = ioctl (fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
@ -718,10 +813,9 @@ Serial::SerialImpl::getRI()
} }
bool bool
Serial::SerialImpl::getCD() Serial::SerialImpl::getCD ()
{ {
if (is_open_ == false) if (is_open_ == false) {
{
throw PortNotOpenedException ("Serial::getCD"); throw PortNotOpenedException ("Serial::getCD");
} }
int s = ioctl (fd_, TIOCMGET, 0); int s = ioctl (fd_, TIOCMGET, 0);
@ -729,7 +823,8 @@ Serial::SerialImpl::getCD()
} }
void void
Serial::SerialImpl::readLock() { Serial::SerialImpl::readLock ()
{
int result = pthread_mutex_lock(&this->read_mutex); int result = pthread_mutex_lock(&this->read_mutex);
if (result) { if (result) {
THROW (IOException, result); THROW (IOException, result);
@ -737,7 +832,8 @@ Serial::SerialImpl::readLock() {
} }
void void
Serial::SerialImpl::readUnlock() { Serial::SerialImpl::readUnlock ()
{
int result = pthread_mutex_unlock(&this->read_mutex); int result = pthread_mutex_unlock(&this->read_mutex);
if (result) { if (result) {
THROW (IOException, result); THROW (IOException, result);
@ -745,7 +841,8 @@ Serial::SerialImpl::readUnlock() {
} }
void void
Serial::SerialImpl::writeLock() { Serial::SerialImpl::writeLock ()
{
int result = pthread_mutex_lock(&this->write_mutex); int result = pthread_mutex_lock(&this->write_mutex);
if (result) { if (result) {
THROW (IOException, result); THROW (IOException, result);
@ -753,7 +850,8 @@ Serial::SerialImpl::writeLock() {
} }
void void
Serial::SerialImpl::writeUnlock() { Serial::SerialImpl::writeUnlock ()
{
int result = pthread_mutex_unlock(&this->write_mutex); int result = pthread_mutex_unlock(&this->write_mutex);
if (result) { if (result) {
THROW (IOException, result); THROW (IOException, result);

549
src/impl/win.cc Normal file
View File

@ -0,0 +1,549 @@
/* Copyright 2012 William Woodall and John Harrison */
#include "serial/impl/win.h"
using std::string;
using std::stringstream;
using std::invalid_argument;
using serial::Serial;
using serial::SerialExecption;
using serial::PortNotOpenedException;
using serial::IOException;
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
bytesize_t bytesize,
parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol)
: port_ (port), fd_ (INVALID_HANDLE_VALUE), is_open_ (false),
baudrate_ (baudrate), parity_ (parity),
bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
{
read_mutex = CreateMutex(NULL, false, NULL);
write_mutex = CreateMutex(NULL, false, NULL);
if (port_.empty () == false)
open ();
}
Serial::SerialImpl::~SerialImpl ()
{
this->close();
CloseHandle(read_mutex);
CloseHandle(write_mutex);
}
void
Serial::SerialImpl::open ()
{
if (port_.empty ()) {
throw invalid_argument ("Empty port is invalid.");
}
if (is_open_ == true) {
throw SerialExecption ("Serial port already open.");
}
fd_ = CreateFile(port_,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (fd_ == INVALID_HANDLE_VALUE) {
DWORD errno = GetLastError();
switch (errno) {
case ERROR_FILE_NOT_FOUND:
stringstream ss;
ss << "Specified port, " << port_ << ", does not exist."
THROW (IOException, ss.str().c_str());
default:
stringstream ss;
ss << "Unknown error opening the serial port: " << errno;
THROW (IOException, ss.str().c_str());
}
}
reconfigurePort();
is_open_ = true;
}
void
Serial::SerialImpl::reconfigurePort ()
{
if (fd_ == INVALID_HANDLE_VALUE) {
// Can only operate on a valid file descriptor
THROW (IOException, "Invalid file descriptor, is the serial port open?");
}
DCB dcbSerialParams = {0};
dcbSerial.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(fd_, &dcbSerialParams)) {
//error getting state
THROW (IOException, "Error getting the serial port state.");
}
// setup baud rate
switch (baudrate_) {
#ifdef CBR_0
case 0: dcbSerialParams.BaudRate = CBR_0; break;
#endif
#ifdef CBR_50
case 50: dcbSerialParams.BaudRate = CBR_50; break;
#endif
#ifdef CBR_75
case 75: dcbSerialParams.BaudRate = CBR_75; break;
#endif
#ifdef CBR_110
case 110: dcbSerialParams.BaudRate = CBR_110; break;
#endif
#ifdef CBR_134
case 134: dcbSerialParams.BaudRate = CBR_134; break;
#endif
#ifdef CBR_150
case 150: dcbSerialParams.BaudRate = CBR_150; break;
#endif
#ifdef CBR_200
case 200: dcbSerialParams.BaudRate = CBR_200; break;
#endif
#ifdef CBR_300
case 300: dcbSerialParams.BaudRate = CBR_300; break;
#endif
#ifdef CBR_600
case 600: dcbSerialParams.BaudRate = CBR_600; break;
#endif
#ifdef CBR_1200
case 1200: dcbSerialParams.BaudRate = CBR_1200; break;
#endif
#ifdef CBR_1800
case 1800: dcbSerialParams.BaudRate = CBR_1800; break;
#endif
#ifdef CBR_2400
case 2400: dcbSerialParams.BaudRate = CBR_2400; break;
#endif
#ifdef CBR_4800
case 4800: dcbSerialParams.BaudRate = CBR_4800; break;
#endif
#ifdef CBR_7200
case 7200: dcbSerialParams.BaudRate = CBR_7200; break;
#endif
#ifdef CBR_9600
case 9600: dcbSerialParams.BaudRate = CBR_9600; break;
#endif
#ifdef CBR_14400
case 14400: dcbSerialParams.BaudRate = CBR_14400; break;
#endif
#ifdef CBR_19200
case 19200: dcbSerialParams.BaudRate = CBR_19200; break;
#endif
#ifdef CBR_28800
case 28800: dcbSerialParams.BaudRate = CBR_28800; break;
#endif
#ifdef CBR_57600
case 57600: dcbSerialParams.BaudRate = CBR_57600; break;
#endif
#ifdef CBR_76800
case 76800: dcbSerialParams.BaudRate = CBR_76800; break;
#endif
#ifdef CBR_38400
case 38400: dcbSerialParams.BaudRate = CBR_38400; break;
#endif
#ifdef CBR_115200
case 115200: dcbSerialParams.BaudRate = CBR_115200; break;
#endif
#ifdef CBR_128000
case 128000: dcbSerialParams.BaudRate = CBR_128000; break;
#endif
#ifdef CBR_153600
case 153600: dcbSerialParams.BaudRate = CBR_153600; break;
#endif
#ifdef CBR_230400
case 230400: dcbSerialParams.BaudRate = CBR_230400; break;
#endif
#ifdef CBR_256000
case 256000: dcbSerialParams.BaudRate = CBR_256000; break;
#endif
#ifdef CBR_460800
case 460800: dcbSerialParams.BaudRate = CBR_460800; break;
#endif
#ifdef CBR_921600
case 921600: dcbSerialParams.BaudRate = CBR_921600; break;
#endif
default:
// Try to blindly assign it
dcbSerialParams.BaudRate = baudrate_;
}
// setup char len
if (bytesize_ == eightbits)
dcbSerialParams.ByteSize = 8;
else if (bytesize_ == sevenbits)
dcbSerialParams.ByteSize = 7;
else if (bytesize_ == sixbits)
dcbSerialParams.ByteSize = 6;
else if (bytesize_ == fivebits)
dcbSerialParams.ByteSize = 5;
else
throw invalid_argument ("invalid char len");
// setup stopbits
if (stopbits_ == stopbits_one)
dcbSerialParams.StopBits = ONESTOPBIT;
else if (stopbits_ == stopbits_one_point_five)
dcbSerialParams.StopBits = ONE5STOPBITS;
else if (stopbits_ == stopbits_two)
dcbSerialParams.StopBits = TWOSTOPBITS;
else
throw invalid_argument ("invalid stop bit");
// setup parity
if (parity_ == parity_none) {
dcbSerialParams.Parity = NOPARITY;
} else if (parity_ == parity_even) {
dcbSerialParams.Parity = EVENPARITY;
} else if (parity_ == parity_odd) {
dcbSerialParams.Parity = ODDPARITY;
} else {
throw invalid_argument ("invalid parity");
}
// activate settings
if(!SetCommState(fd_, &dcbSerialParams)){
THROW (IOException, "Error setting serial port settings.");
}
}
void
Serial::SerialImpl::close ()
{
if (is_open_ == true) {
if (fd_ != INVALID_HANDLE_VALUE) {
CloseHandle(fd_);
fd_ = INVALID_HANDLE_VALUE;
}
is_open_ = false;
}
}
bool
Serial::SerialImpl::isOpen () const
{
return is_open_;
}
size_t
Serial::SerialImpl::available ()
{
THROW (IOException, "available is not implemented on Windows.");
}
size_t
Serial::SerialImpl::read (uint8_t *buf, size_t size)
{
if (!is_open_) {
throw PortNotOpenedException ("Serial::read");
}
DWORD bytes_read;
if (!ReadFile(fd_, buf, size, &bytes_read, NULL)) {
stringstream ss;
ss << "Error while reading from the serial port: " << GetLastError();
THROW (IOException, ss.str().c_str());
}
return reinterpret_cast<size_t> (bytes_read);
}
size_t
Serial::SerialImpl::write (const uint8_t *data, size_t length)
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::write");
}
DWORD bytes_written;
if (!ReadFile(fd_, buf, size, &bytes_written, NULL)) {
stringstream ss;
ss << "Error while writing to the serial port: " << GetLastError();
THROW (IOException, ss.str().c_str());
}
return reinterpret_cast<size_t> (bytes_written);
}
void
Serial::SerialImpl::setPort (const string &port)
{
port_ = port;
}
string
Serial::SerialImpl::getPort () const
{
return port_;
}
void
Serial::SerialImpl::setTimeout (serial::Timeout &timeout)
{
timeout_ = timeout;
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout;
timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant;
timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier;
timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant;
timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier;
if(!SetCommTimeouts(fd_, &timeouts)){
THROW (IOException, "Error setting timeouts.");
}
}
serial::Timeout
Serial::SerialImpl::getTimeout () const
{
return timeout_;
}
void
Serial::SerialImpl::setBaudrate (unsigned long baudrate)
{
baudrate_ = baudrate;
if (is_open_)
reconfigurePort ();
}
unsigned long
Serial::SerialImpl::getBaudrate () const
{
return baudrate_;
}
void
Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
{
bytesize_ = bytesize;
if (is_open_)
reconfigurePort ();
}
serial::bytesize_t
Serial::SerialImpl::getBytesize () const
{
return bytesize_;
}
void
Serial::SerialImpl::setParity (serial::parity_t parity)
{
parity_ = parity;
if (is_open_)
reconfigurePort ();
}
serial::parity_t
Serial::SerialImpl::getParity () const
{
return parity_;
}
void
Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
{
stopbits_ = stopbits;
if (is_open_)
reconfigurePort ();
}
serial::stopbits_t
Serial::SerialImpl::getStopbits () const
{
return stopbits_;
}
void
Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
{
flowcontrol_ = flowcontrol;
if (is_open_)
reconfigurePort ();
}
serial::flowcontrol_t
Serial::SerialImpl::getFlowcontrol () const
{
return flowcontrol_;
}
void
Serial::SerialImpl::flush ()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::flush");
}
FlushFileBuffers (fd_);
}
void
Serial::SerialImpl::flushInput ()
{
THROW (IOException, "flushInput is not supported on Windows.");
}
void
Serial::SerialImpl::flushOutput ()
{
THROW (IOException, "flushOutput is not supported on Windows.");
}
void
Serial::SerialImpl::sendBreak (int duration)
{
THROW (IOException, "sendBreak is not supported on Windows.");
}
void
Serial::SerialImpl::setBreak (bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::setBreak");
}
if (level) {
EscapeCommFunction (fd_, SETBREAK);
} else {
EscapeCommFunction (fd_, CLRBREAK);
}
}
void
Serial::SerialImpl::setRTS (bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::setRTS");
}
if (level) {
EscapeCommFunction (fd_, SETRTS);
} else {
EscapeCommFunction (fd_, CLRRTS);
}
}
void
Serial::SerialImpl::setDTR (bool level)
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::setDTR");
}
if (level) {
EscapeCommFunction (fd_, SETDTR);
} else {
EscapeCommFunction (fd_, CLRDTR);
}
}
bool
Serial::SerialImpl::waitForChange ()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::waitForChange");
}
DWORD dwCommEvent;
if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
// Error setting communications mask
return false;
}
if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
// An error occurred waiting for the event.
return false;
} else {
// Event has occurred.
return true;
}
}
bool
Serial::SerialImpl::getCTS ()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::getCTS");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus))
// Error in GetCommModemStatus;
THROW (IOException, "Error getting the status of the CTS line.");
return MS_CTS_ON & dwModemStatus;
}
bool
Serial::SerialImpl::getDSR ()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::getDSR");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus))
// Error in GetCommModemStatus;
THROW (IOException, "Error getting the status of the DSR line.");
return MS_DSR_ON & dwModemStatus;
}
bool
Serial::SerialImpl::getRI()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::getRI");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus))
// Error in GetCommModemStatus;
THROW (IOException, "Error getting the status of the DSR line.");
return MS_RING_ON & dwModemStatus;
}
bool
Serial::SerialImpl::getCD()
{
if (is_open_ == false) {
throw PortNotOpenedException ("Serial::getCD");
}
DWORD dwModemStatus;
if (!GetCommModemStatus(fd_, &dwModemStatus))
// Error in GetCommModemStatus;
THROW (IOException, "Error getting the status of the DSR line.");
return MS_RLSD_ON & dwModemStatus;
}
void
Serial::SerialImpl::readLock()
{
if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
THROW (IOException, "Error claiming read mutex.");
}
}
void
Serial::SerialImpl::readUnlock()
{
if (!ReleaseMutex(read_mutex)) {
THROW (IOException, "Error releasing read mutex.");
}
}
void
Serial::SerialImpl::writeLock()
{
if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
THROW (IOException, "Error claiming write mutex.");
}
}
void
Serial::SerialImpl::writeUnlock()
{
if (!ReleaseMutex(write_mutex)) {
THROW (IOException, "Error releasing write mutex.");
}
}

View File

@ -1,670 +0,0 @@
/* Copyright 2012 William Woodall and John Harrison */
#include "serial/impl/windows.h"
using std::string;
using std::invalid_argument;
using serial::Serial;
using serial::SerialExecption;
using serial::PortNotOpenedException;
using serial::IOException;
Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
long timeout, bytesize_t bytesize,
parity_t parity, stopbits_t stopbits,
flowcontrol_t flowcontrol)
: port_ (port), fd_ (-1), isOpen_ (false), xonxoff_ (true), rtscts_ (false),
timeout_ (timeout), baudrate_ (baudrate), parity_ (parity), bytesize_ (bytesize),
stopbits_ (stopbits), flowcontrol_ (flowcontrol)
{
if (port_.empty () == false)
open ();
}
Serial::SerialImpl::~SerialImpl ()
{
close();
}
void
Serial::SerialImpl::open ()
{
if (port_.empty())
{
throw invalid_argument ("bad port specified");
}
if (isOpen_ == true)
{
throw SerialExecption ("port already open");
}
fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_ == -1)
{
switch (errno)
{
case EINTR:
// Recurse because this is a recoverable error.
open ();
return;
case ENFILE:
case EMFILE:
throw IOException ("to many file handles open");
break;
default:
throw IOException (errno);
}
}
reconfigurePort();
isOpen_ = true;
}
void
Serial::SerialImpl::reconfigurePort ()
{
if (fd_ == -1)
{
// Can only operate on a valid file descriptor
throw IOException ("invalid file descriptor");
}
struct termios options; // The options for the file descriptor
if (tcgetattr(fd_, &options) == -1)
{
throw IOException ("::tcgetattr");
}
// set up raw mode / no echo / binary
options.c_cflag |= (unsigned long) (CLOCAL|CREAD);
options.c_lflag &= (unsigned long) ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|
ISIG|IEXTEN); //|ECHOPRT
options.c_oflag &= (unsigned long) ~(OPOST);
options.c_iflag &= (unsigned long) ~(INLCR|IGNCR|ICRNL|IGNBRK);
#ifdef IUCLC
options.c_iflag &= (unsigned long) ~IUCLC;
#endif
#ifdef PARMRK
options.c_iflag &= (unsigned long) ~PARMRK;
#endif
// setup baud rate
bool custom_baud = false;
speed_t baud;
switch (baudrate_)
{
#ifdef B0
case 0: baud = B0; break;
#endif
#ifdef B50
case 50: baud = B50; break;
#endif
#ifdef B75
case 75: baud = B75; break;
#endif
#ifdef B110
case 110: baud = B110; break;
#endif
#ifdef B134
case 134: baud = B134; break;
#endif
#ifdef B150
case 150: baud = B150; break;
#endif
#ifdef B200
case 200: baud = B200; break;
#endif
#ifdef B300
case 300: baud = B300; break;
#endif
#ifdef B600
case 600: baud = B600; break;
#endif
#ifdef B1200
case 1200: baud = B1200; break;
#endif
#ifdef B1800
case 1800: baud = B1800; break;
#endif
#ifdef B2400
case 2400: baud = B2400; break;
#endif
#ifdef B4800
case 4800: baud = B4800; break;
#endif
#ifdef B7200
case 7200: baud = B7200; break;
#endif
#ifdef B9600
case 9600: baud = B9600; break;
#endif
#ifdef B14400
case 14400: baud = B14400; break;
#endif
#ifdef B19200
case 19200: baud = B19200; break;
#endif
#ifdef B28800
case 28800: baud = B28800; break;
#endif
#ifdef B57600
case 57600: baud = B57600; break;
#endif
#ifdef B76800
case 76800: baud = B76800; break;
#endif
#ifdef B38400
case 38400: baud = B38400; break;
#endif
#ifdef B115200
case 115200: baud = B115200; break;
#endif
#ifdef B128000
case 128000: baud = B128000; break;
#endif
#ifdef B153600
case 153600: baud = B153600; break;
#endif
#ifdef B230400
case 230400: baud = B230400; break;
#endif
#ifdef B256000
case 256000: baud = B256000; break;
#endif
#ifdef B460800
case 460800: baud = B460800; break;
#endif
#ifdef B921600
case 921600: baud = B921600; break;
#endif
default:
custom_baud = true;
// Mac OS X 10.x Support
#if defined(__APPLE__) && defined(__MACH__)
#define IOSSIOSPEED _IOW('T', 2, speed_t)
int new_baud = static_cast<int> (baudrate_);
if (ioctl (fd_, IOSSIOSPEED, &new_baud, 1) < 0)
{
throw IOException (errno);
}
// Linux Support
#elif defined(__linux__)
struct serial_struct ser;
ioctl(fd_, TIOCGSERIAL, &ser);
// set custom divisor
ser.custom_divisor = ser.baud_base / baudrate_;
// update flags
ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST;
if (ioctl(fd_, TIOCSSERIAL, ser) < 0)
{
throw IOException (errno);
}
#else
throw invalid_argument ("OS does not currently support custom bauds");
#endif
}
if (custom_baud == false)
{
#ifdef _BSD_SOURCE
::cfsetspeed(&options, baud);
#else
::cfsetispeed(&options, baud);
::cfsetospeed(&options, baud);
#endif
}
// setup char len
options.c_cflag &= (unsigned long) ~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 invalid_argument ("invalid char len");
// setup stopbits
if (stopbits_ == STOPBITS_ONE)
options.c_cflag &= (unsigned long) ~(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 invalid_argument ("invalid stop bit");
// setup parity
options.c_iflag &= (unsigned long) ~(INPCK|ISTRIP);
if (parity_ == PARITY_NONE)
{
options.c_cflag &= (unsigned long) ~(PARENB|PARODD);
}
else if (parity_ == PARITY_EVEN)
{
options.c_cflag &= (unsigned long) ~(PARODD);
options.c_cflag |= (PARENB);
}
else if (parity_ == PARITY_ODD)
{
options.c_cflag |= (PARENB|PARODD);
}
else
{
throw invalid_argument ("invalid parity");
}
// setup flow control
// xonxoff
#ifdef IXANY
if (xonxoff_)
options.c_iflag |= (IXON|IXOFF); //|IXANY)
else
options.c_iflag &= (unsigned long) ~(IXON|IXOFF|IXANY);
#else
if (xonxoff_)
options.c_iflag |= (IXON|IXOFF);
else
options.c_iflag &= (unsigned long) ~(IXON|IXOFF);
#endif
// rtscts
#ifdef CRTSCTS
if (rtscts_)
options.c_cflag |= (CRTSCTS);
else
options.c_cflag &= (unsigned long) ~(CRTSCTS);
#elif defined CNEW_RTSCTS
if (rtscts_)
options.c_cflag |= (CNEW_RTSCTS);
else
options.c_cflag &= (unsigned long) ~(CNEW_RTSCTS);
#else
#error "OS Support seems wrong."
#endif
options.c_cc[VMIN] = 1; // Minimum of 1 character in the buffer
options.c_cc[VTIME] = 0; // timeout on waiting for new data
// activate settings
::tcsetattr (fd_, TCSANOW, &options);
}
void
Serial::SerialImpl::close ()
{
if (isOpen_ == true)
{
if (fd_ != -1)
{
::close (fd_); // Ignoring the outcome
fd_ = -1;
}
isOpen_ = false;
}
}
bool
Serial::SerialImpl::isOpen () const
{
return isOpen_;
}
size_t
Serial::SerialImpl::available ()
{
if (!isOpen_)
{
return 0;
}
int count = 0;
int result = ioctl (fd_, TIOCINQ, &count);
if (result == 0)
{
return static_cast<size_t> (count);
}
else
{
throw IOException (errno);
}
}
size_t
Serial::SerialImpl::read (char* buf, size_t size)
{
if (!isOpen_)
{
throw PortNotOpenedException ("Serial::read");
}
fd_set readfds;
ssize_t bytes_read = 0;
int count = 0;
while (true)
{
count++;
if (timeout_ != -1)
{
FD_ZERO (&readfds);
FD_SET (fd_, &readfds);
struct timeval timeout;
timeout.tv_sec = timeout_ / 1000;
timeout.tv_usec = static_cast<int> (timeout_ % 1000) * 1000;
int r = select (fd_ + 1, &readfds, NULL, NULL, &timeout);
if (r == -1 && errno == EINTR)
continue;
if (r == -1)
{
throw IOException (errno);
}
}
if (timeout_ == -1 || FD_ISSET (fd_, &readfds))
{
bytes_read = ::read (fd_, buf, size);
// read should always return some data as select reported it was
// ready to read when we get to this point.
if (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;
}
else
{
break;
}
}
return static_cast<size_t> (bytes_read);
}
size_t
Serial::SerialImpl::write (const string &data)
{
if (isOpen_ == false)
{
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)
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
Serial::SerialImpl::setPort (const string &port)
{
port_ = port;
}
string
Serial::SerialImpl::getPort () const
{
return port_;
}
void
Serial::SerialImpl::setTimeout (long timeout)
{
timeout_ = timeout;
}
long
Serial::SerialImpl::getTimeout () const
{
return timeout_;
}
void
Serial::SerialImpl::setBaudrate (unsigned long baudrate)
{
baudrate_ = baudrate;
if (isOpen_)
reconfigurePort ();
}
unsigned long
Serial::SerialImpl::getBaudrate () const
{
return baudrate_;
}
void
Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
{
bytesize_ = bytesize;
if (isOpen_)
reconfigurePort ();
}
serial::bytesize_t
Serial::SerialImpl::getBytesize () const
{
return bytesize_;
}
void
Serial::SerialImpl::setParity (serial::parity_t parity)
{
parity_ = parity;
if (isOpen_)
reconfigurePort ();
}
serial::parity_t
Serial::SerialImpl::getParity () const
{
return parity_;
}
void
Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
{
stopbits_ = stopbits;
if (isOpen_)
reconfigurePort ();
}
serial::stopbits_t
Serial::SerialImpl::getStopbits () const
{
return stopbits_;
}
void
Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
{
flowcontrol_ = flowcontrol;
if (isOpen_)
reconfigurePort ();
}
serial::flowcontrol_t
Serial::SerialImpl::getFlowcontrol () const
{
return flowcontrol_;
}
void
Serial::SerialImpl::flush ()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flush");
}
tcdrain (fd_);
}
void
Serial::SerialImpl::flushInput ()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flushInput");
}
tcflush (fd_, TCIFLUSH);
}
void
Serial::SerialImpl::flushOutput ()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::flushOutput");
}
tcflush (fd_, TCOFLUSH);
}
void
Serial::SerialImpl::sendBreak (int duration)
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::sendBreak");
}
tcsendbreak (fd_, static_cast<int> (duration/4));
}
void
Serial::SerialImpl::setBreak (bool level)
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setBreak");
}
if (level)
{
ioctl (fd_, TIOCSBRK);
}
else {
ioctl (fd_, TIOCCBRK);
}
}
void
Serial::SerialImpl::setRTS (bool level)
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setRTS");
}
if (level)
{
ioctl (fd_, TIOCMBIS, TIOCM_RTS);
}
else {
ioctl (fd_, TIOCMBIC, TIOCM_RTS);
}
}
void
Serial::SerialImpl::setDTR (bool level)
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::setDTR");
}
if (level)
{
ioctl (fd_, TIOCMBIS, TIOCM_DTR);
}
else
{
ioctl (fd_, TIOCMBIC, TIOCM_DTR);
}
}
bool
Serial::SerialImpl::getCTS ()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getCTS");
}
int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_CTS) != 0;
}
bool
Serial::SerialImpl::getDSR()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getDSR");
}
int s = ioctl(fd_, TIOCMGET, 0);
return (s & TIOCM_DSR) != 0;
}
bool
Serial::SerialImpl::getRI()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getRI");
}
int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_RI) != 0;
}
bool
Serial::SerialImpl::getCD()
{
if (isOpen_ == false)
{
throw PortNotOpenedException ("Serial::getCD");
}
int s = ioctl (fd_, TIOCMGET, 0);
return (s & TIOCM_CD) != 0;
}

View File

@ -33,6 +33,11 @@ public:
this->pimpl_->readUnlock(); this->pimpl_->readUnlock();
} }
private: private:
// Disable copy constructors
ScopedReadLock(const ScopedReadLock&);
void operator=(const ScopedReadLock&);
const ScopedReadLock& operator=(ScopedReadLock);
SerialImpl *pimpl_; SerialImpl *pimpl_;
}; };
@ -45,16 +50,20 @@ public:
this->pimpl_->writeUnlock(); this->pimpl_->writeUnlock();
} }
private: private:
// Disable copy constructors
ScopedWriteLock(const ScopedWriteLock&);
void operator=(const ScopedWriteLock&);
const ScopedWriteLock& operator=(ScopedWriteLock);
SerialImpl *pimpl_; SerialImpl *pimpl_;
}; };
Serial::Serial (const string &port, unsigned long baudrate, long timeout, Serial::Serial (const string &port, uint32_t baudrate, Timeout 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)
: read_cache_("") : read_cache_(""), pimpl_(new SerialImpl (port, baudrate, bytesize, parity,
stopbits, flowcontrol))
{ {
pimpl_ = new SerialImpl (port, baudrate, timeout, bytesize, parity, pimpl_->setTimeout(timeout);
stopbits, flowcontrol);
} }
Serial::~Serial () Serial::~Serial ()
@ -87,23 +96,23 @@ Serial::available ()
} }
size_t size_t
Serial::read_ (unsigned char *buffer, size_t size) Serial::read_ (uint8_t *buffer, size_t size)
{ {
return this->pimpl_->read (buffer, size); return this->pimpl_->read (buffer, size);
} }
size_t size_t
Serial::read (unsigned char *buffer, size_t size) Serial::read (uint8_t *buffer, size_t size)
{ {
ScopedReadLock (this->pimpl_); ScopedReadLock (this->pimpl_);
return this->pimpl_->read (buffer, size); return this->pimpl_->read (buffer, size);
} }
size_t size_t
Serial::read (std::vector<unsigned char> &buffer, size_t size) Serial::read (std::vector<uint8_t> &buffer, size_t size)
{ {
ScopedReadLock (this->pimpl_); ScopedReadLock (this->pimpl_);
unsigned char *buffer_ = new unsigned char[size]; uint8_t *buffer_ = new uint8_t[size];
size_t bytes_read = this->pimpl_->read (buffer_, size); size_t bytes_read = this->pimpl_->read (buffer_, size);
buffer.insert (buffer.end (), buffer_, buffer_+bytes_read); buffer.insert (buffer.end (), buffer_, buffer_+bytes_read);
delete[] buffer_; delete[] buffer_;
@ -114,7 +123,7 @@ size_t
Serial::read (std::string &buffer, size_t size) Serial::read (std::string &buffer, size_t size)
{ {
ScopedReadLock (this->pimpl_); ScopedReadLock (this->pimpl_);
unsigned char *buffer_ = new unsigned char[size]; uint8_t *buffer_ = new uint8_t[size];
size_t bytes_read = this->pimpl_->read (buffer_, size); size_t bytes_read = this->pimpl_->read (buffer_, size);
buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read); buffer.append (reinterpret_cast<const char*>(buffer_), bytes_read);
delete[] buffer_; delete[] buffer_;
@ -134,8 +143,8 @@ Serial::readline (string &buffer, size_t size, string eol)
{ {
ScopedReadLock (this->pimpl_); ScopedReadLock (this->pimpl_);
size_t eol_len = eol.length (); size_t eol_len = eol.length ();
unsigned char *buffer_ = static_cast<unsigned char*> uint8_t *buffer_ = static_cast<uint8_t*>
(alloca (size * sizeof (unsigned char))); (alloca (size * sizeof (uint8_t)));
size_t read_so_far = 0; size_t read_so_far = 0;
while (true) while (true)
{ {
@ -170,8 +179,8 @@ Serial::readlines (size_t size, string eol)
ScopedReadLock (this->pimpl_); ScopedReadLock (this->pimpl_);
std::vector<std::string> lines; std::vector<std::string> lines;
size_t eol_len = eol.length (); size_t eol_len = eol.length ();
unsigned char *buffer_ = static_cast<unsigned char*> uint8_t *buffer_ = static_cast<uint8_t*>
(alloca (size * sizeof (unsigned char))); (alloca (size * sizeof (uint8_t)));
size_t read_so_far = 0; size_t read_so_far = 0;
size_t start_of_line = 0; size_t start_of_line = 0;
while (read_so_far < size) { while (read_so_far < size) {
@ -209,7 +218,28 @@ size_t
Serial::write (const string &data) Serial::write (const string &data)
{ {
ScopedWriteLock(this->pimpl_); ScopedWriteLock(this->pimpl_);
return pimpl_->write (data); return this->write_ (reinterpret_cast<const uint8_t*>(data.c_str()),
data.length());
}
size_t
Serial::write (const std::vector<uint8_t> &data)
{
ScopedWriteLock(this->pimpl_);
return this->write_ (&data[0], data.size());
}
size_t
Serial::write (const uint8_t *data, size_t size)
{
ScopedWriteLock(this->pimpl_);
return this->write_(data, size);
}
size_t
Serial::write_ (const uint8_t *data, size_t length)
{
return pimpl_->write (data, length);
} }
void void
@ -230,26 +260,26 @@ Serial::getPort () const
} }
void void
Serial::setTimeout (long timeout) Serial::setTimeout (serial::Timeout &timeout)
{ {
pimpl_->setTimeout (timeout); pimpl_->setTimeout (timeout);
} }
long serial::Timeout
Serial::getTimeout () const { Serial::getTimeout () const {
return pimpl_->getTimeout (); return pimpl_->getTimeout ();
} }
void void
Serial::setBaudrate (unsigned long baudrate) Serial::setBaudrate (uint32_t baudrate)
{ {
pimpl_->setBaudrate (baudrate); pimpl_->setBaudrate (baudrate);
} }
unsigned long uint32_t
Serial::getBaudrate () const Serial::getBaudrate () const
{ {
return pimpl_->getBaudrate (); return uint32_t(pimpl_->getBaudrate ());
} }
void void
@ -341,6 +371,11 @@ void Serial::setDTR (bool level)
pimpl_->setDTR (level); pimpl_->setDTR (level);
} }
bool Serial::waitForChange()
{
return pimpl_->waitForChange();
}
bool Serial::getCTS () bool Serial::getCTS ()
{ {
return pimpl_->getCTS (); return pimpl_->getCTS ();